{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "63e8c422-2c7d-4090-b73b-3a10ed1e4f17",
   "metadata": {},
   "source": [
    "基础环境：https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2021.11-Windows-x86_64.exe  \n",
    "- pandas==1.3.4\n",
    "- numpy==1.20.3"
   ]
  },
  {
   "cell_type": "raw",
   "id": "93af9ef2-463b-4792-bc22-e5c25a0ca443",
   "metadata": {},
   "source": [
    "pip install flask==2.1.0 -i https://pypi.douban.com/simple\n",
    "pip install flask-cors==3.0.8 -i https://pypi.douban.com/simple\n",
    "pip install jinja2==3.1.2 -i https://pypi.douban.com/simple"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de31459c-e9b5-4756-9f77-0fbc96ec431c",
   "metadata": {},
   "source": [
    "# Flask基础"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "390136a1-ac72-49e8-814d-551a951b5efe",
   "metadata": {},
   "source": [
    "W3C菜鸟教程：https://www.w3cschool.cn/flask/"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49d248c2-5862-497f-9ae8-230004d37678",
   "metadata": {
    "tags": []
   },
   "source": [
    "## 标准模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "954a4e9b-7fe2-4f1b-b7ea-b3096d7b7c40",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app '__main__' (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to bili-afan space!'\n",
    "app.run()"
   ]
  },
  {
   "cell_type": "raw",
   "id": "70d20dc7-9221-42f2-916f-e0f1307c2f94",
   "metadata": {},
   "source": [
    " * Serving Flask app '__main__' (lazy loading)\n",
    " * Environment: production\n",
    "   WARNING: This is a development server. Do not use it in a production deployment.\n",
    "   Use a production WSGI server instead.\n",
    " * Debug mode: off\n",
    " * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ea2be0c-b06a-441f-a29a-74e60ed3e720",
   "metadata": {},
   "source": [
    "一旦运行成功，服务一直在运行中，必须要停止才能执行这个jupyter的其他命令"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32be2b3a-7314-4107-990f-d09f5beb0368",
   "metadata": {},
   "source": [
    "### 什么是\\_\\_name\\_\\_"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91a472a0-2ff6-4e37-bd88-bae8447301ab",
   "metadata": {},
   "source": [
    "它的作用主要是用来区分当前模块是独立运行还是被调用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "a3327035-03f8-4d0e-bfa6-9abed81787e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "from name import name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4dbfa1d3-e5fa-43b8-83f0-8a5652d04366",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name\n"
     ]
    }
   ],
   "source": [
    "name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "88d66f61-ecb2-408d-ae9f-740ba83b04a4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__main__ 1\n"
     ]
    }
   ],
   "source": [
    "def name():\n",
    "    print(__name__, 1)\n",
    "name()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6e58b9c-c16e-4880-833b-ac831de5cfce",
   "metadata": {
    "tags": []
   },
   "source": [
    "### 什么是端口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ded4f8cc-6cf5-407c-88e4-95d2cd3e1ab0",
   "metadata": {},
   "outputs": [],
   "source": [
    "from flask import Flask\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to bili-afan space!'\n",
    "\n",
    "# app.run(port=8888)\n",
    "# www.baidu.com:80  www.baidu.com:81\n",
    "app.run(port=5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b09ac85e-3db5-4b0f-8239-9e368e0c3f27",
   "metadata": {},
   "source": [
    "### 什么是host"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a403e572-b4c1-4787-a0f5-2c64c55d701d",
   "metadata": {},
   "source": [
    "特殊的host：\n",
    "- 127.0.0.1，也即localhost，也即自己，是一个环回地址\n",
    "- 0.0.0.0，对外开放的IP，是网络中真正的本机地址"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "dd62dc3c-8e49-4a32-83eb-be0849269513",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app '__main__' (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on all addresses (0.0.0.0)\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://127.0.0.1:5000\n",
      " * Running on http://192.168.1.8:5000 (Press CTRL+C to quit)\n",
      "192.168.1.10 - - [05/Jun/2022 02:25:25] \"GET / HTTP/1.1\" 200 -\n",
      "192.168.1.10 - - [05/Jun/2022 02:25:25] \"GET / HTTP/1.1\" 200 -\n",
      "192.168.1.10 - - [05/Jun/2022 02:25:25] \"GET /favicon.ico HTTP/1.1\" 404 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to bili-afan space!'\n",
    "\n",
    "# app.run(host='127.0.0.2', port=5000)\n",
    "# app.run(host='127.0.0.1', port=5000) \n",
    "app.run(host='0.0.0.0', port=5000)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "5f628fb7-9dcc-4b25-b209-631ed67d5c0e",
   "metadata": {},
   "source": [
    " * Serving Flask app '__main__' (lazy loading)\n",
    " * Environment: production\n",
    "   WARNING: This is a development server. Do not use it in a production deployment.\n",
    "   Use a production WSGI server instead.\n",
    " * Debug mode: off\n",
    " * Running on all addresses (0.0.0.0)\n",
    "   WARNING: This is a development server. Do not use it in a production deployment.\n",
    " * Running on http://127.0.0.1:5000\n",
    " * Running on http://192.168.1.8:5000 (Press CTRL+C to quit)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f12352d2-c846-4c16-a2bc-30aff90c1eec",
   "metadata": {},
   "source": [
    "### 什么是路由"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b84e513e-69ba-48ca-9f46-ceb2372c59cf",
   "metadata": {},
   "source": [
    "route就是一条路由，他将一个URL路径和一个函数进行映射  \n",
    "这将一个受程序控制的动态资源，变成了类似静态资源文件夹结构的映射"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f2fac2a6-ee44-4ec5-a174-302e3843889e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app '__main__' (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on all addresses (0.0.0.0)\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://127.0.0.1:5000\n",
      " * Running on http://192.168.1.8:5000 (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [05/Jun/2022 02:43:59] \"GET / HTTP/1.1\" 200 -\n",
      "127.0.0.1 - - [05/Jun/2022 02:44:06] \"GET /afan HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to bili-afan space!'\n",
    "\n",
    "@app.route('/afan')\n",
    "def introduction(): # 名称不能相同\n",
    "    return 'Afan is a lazy UP in Feynman area.'\n",
    "\n",
    "# app.run(host='127.0.0.2', port=5000)\n",
    "# app.run(host='127.0.0.1', port=5000)\n",
    "app.run(host='0.0.0.0', port=5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aaf85ff4-5675-4445-8fd9-1cad07ffea77",
   "metadata": {},
   "source": [
    "### 返回值"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fcef7adc-a8f8-4a6e-b1d6-2330559332c9",
   "metadata": {},
   "source": [
    "string, dict, tuple"
   ]
  },
  {
   "cell_type": "raw",
   "id": "e676db8f-1702-4a2c-8b4f-9853583b4699",
   "metadata": {},
   "source": [
    "from flask import Flask\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 1\n",
    "app.run(host='0.0.0.0', port=5000)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "9775355a-d299-4f01-aec4-3343ba7c9166",
   "metadata": {},
   "source": [
    "TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a int."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0ef8cf73-ef89-4b63-81bc-f41d249c8585",
   "metadata": {},
   "source": [
    "# Echarts介绍"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d712a86-686b-4cec-8c8f-5e6564c46caa",
   "metadata": {},
   "source": [
    "ECharts是一款基于JavaScript的数据可视化图表库，提供直观，生动，可交互，可个性化定制的数据可视化图表。ECharts最初由百度团队开源，并于2018年初捐赠给Apache基金会，成为ASF孵化级项目"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8214e93-ae99-42b7-b208-b3698e70d7d2",
   "metadata": {},
   "source": [
    "Echarts是一个纯JavaScript图表库，缩写来自Enterprise Charts，商业级数据图表。它可以流畅的运行在PC和移动设备上，兼容当前绝大部分浏览器（IE6/7/8/9/10/11，chrome，firefox，Safari等），底层依赖轻量级的Canvas类库ZRender，提供直观，生动，可交互，可高度个性化定制的数据可视化图表。创新的拖拽重计算、数据视图、值域漫游等特性大大增强了用户体验，赋予了用户对数据进行挖掘、整合的能力。涵盖各行业图表，满足各种需求。其遵循 Apache-2.0 开源协议，免费商用。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "051c8b22-a8ad-4753-9682-23a71e2beeb9",
   "metadata": {},
   "source": [
    "官网：https://echarts.apache.org/zh/index.html  \n",
    "官方入门：https://echarts.apache.org/handbook/zh/get-started/"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99851df7-5588-466e-8c1c-42e0c7f90b00",
   "metadata": {},
   "source": [
    "## 静态示例"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9364751-ff7d-493c-b0ff-2498757fd0cd",
   "metadata": {},
   "source": [
    "### Echarts和Pyecharts的关系？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d693b267-2fd5-466e-a1a8-fdbfd652fcac",
   "metadata": {},
   "source": [
    "- Echarts在前后端开发场景展现数据\n",
    "- Pyecharts在数据分析场景展现数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f506c109-9b54-44ec-b05a-bb23b23535e5",
   "metadata": {},
   "source": [
    "\n",
    "引用其他人评价：https://article.itxueyuan.com/xnmRZe"
   ]
  },
  {
   "cell_type": "raw",
   "id": "a7df7136-2ed0-42c6-af96-b351ff24ff1b",
   "metadata": {
    "tags": []
   },
   "source": [
    "ECharts是⼀个由百度开发的纯 Javascript 的图表库，pyecharts是某三位⼤佬将ECharts移植到Python项⽬中的产物，在Python⽹站中\n",
    "可以更轻松的接⼊图表，但是个⼈感觉pyecharts⽐ECharts还是局限很⼤的，pyecharts0.5.x版本就更为缩⽔了，由于项⽬之前⽤的是\n",
    "pyecharts0.5.11版本，图表⽐较少，不⾜以解决问题，甚⾄⾃⼰⽤js实现了两个图表来使⽤，美观度⽐ECharts还是逊⾊不少，如果将项⽬\n",
    "迁移到新版pyecharts v1.0.0则更为⿇烦，就直接在原来的项⽬中引⼊echarts库来混合使⽤，pyecharts v1.0.0虽然完善了不少问题，但是加⼊了新的配置规则，学习起来增加了不少负担，灵活度也没有echarts好，个⼈建议如果项⽬中使⽤的图表不是很复杂，数据静态的可以使⽤\n",
    "pyecharts，复杂点的还是尽量使⽤echarts⽐较⽅便。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e7d0e4c-a5f8-49d0-8bbc-8fc4b6de23aa",
   "metadata": {},
   "source": [
    "### Javascript是什么"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9d59c37-fe92-4a84-8a5a-351793a2548a",
   "metadata": {},
   "source": [
    "Javascript是一门独立的语言，脚本语言，没有编译过程，解释运行；主要应用在客户端，在服务器端也有所应用(Node.js)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba0eeb1e-f2e9-4457-9f92-640c4e6b6ec9",
   "metadata": {},
   "source": [
    "#### 使用方法"
   ]
  },
  {
   "cell_type": "raw",
   "id": "293492c1-c792-45d1-a5ae-0600745fd773",
   "metadata": {},
   "source": [
    " 方式一：在html中的head标签中书写<script>标签，在标签内部写js代码\n",
    "    <script type=\"text/javascript\"></script>\n",
    " 方式二：引入外部文件中的js代码，在head标签中书写<script>标签，通过标签的src属性引入外部写好的js文件中的js，\n",
    "    <script type=\"text/javascript\" src=\"demo1.js\"></script>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "add60d46-7861-4052-9649-bae7f14b988e",
   "metadata": {},
   "source": [
    "#### 基本语法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25e10970-acb2-4aa2-9ce2-09a89532bfd3",
   "metadata": {},
   "source": [
    "- 弱类型，所有都能用var来定义\n",
    "- 变量类型和Python类似，有字典、列表、字符串、数值等\n",
    "- 也可以定义函数、对象来复用代码执行\n",
    "- 是脚本语言，没有编译过程，和Python一样，没有编译成exe等二进制代码"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12132408-7e09-4276-8dba-2666b058313c",
   "metadata": {},
   "source": [
    "DOM全拼为Document Object Model是一种用于HTML和XML文档的编程接口，给文档提供了一种结构化的表示方法"
   ]
  },
  {
   "cell_type": "raw",
   "id": "ab9686f4-3e67-42b3-9f38-634b58b440cc",
   "metadata": {},
   "source": [
    "  // 基于准备好的dom，初始化echarts实例\n",
    "  var myChart = echarts.init(document.getElementById('main'));\n",
    "\n",
    "  // 指定图表的配置项和数据\n",
    "  var option = {\n",
    "    title: {\n",
    "      text: 'ECharts 入门示例'\n",
    "    },\n",
    "    tooltip: {},\n",
    "    legend: {\n",
    "      data: ['销量']\n",
    "    },\n",
    "    xAxis: {\n",
    "      data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']\n",
    "    },\n",
    "    yAxis: {},\n",
    "    series: [\n",
    "      {\n",
    "        name: '销量',\n",
    "        type: 'bar',\n",
    "        data: [5, 20, 36, 10, 10, 20]\n",
    "      }\n",
    "    ]\n",
    "  };\n",
    "\n",
    "  // 使用刚指定的配置项和数据显示图表。\n",
    "  myChart.setOption(option);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15138714-66b3-438e-8720-0f8aeee11542",
   "metadata": {},
   "source": [
    "### jquery"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47058933-0a63-441c-a3fe-3cd1d1a87eda",
   "metadata": {},
   "source": [
    "W3C教程：https://www.w3school.com.cn/jquery/index.asp"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73726026-8d43-4ab9-8e2a-a7e1977fc2c2",
   "metadata": {},
   "source": [
    "jquery 是一个“写的更少，但做的更多”的轻量级 JavaScript 函数库，在它基础上封装开发，此处echarts大量引用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3346ed49-7b87-4c87-801a-8ad705173158",
   "metadata": {},
   "source": [
    "jQuery是一个快速、简洁的JavaScript框架，是继Prototype之后又一个优秀的JavaScript代码库（框架）于2006年1月由John Resig发布。jQuery设计的宗旨是“write Less，Do More”，即倡导写更少的代码，做更多的事情。它封装JavaScript常用的功能代码，提供一种简便的JavaScript设计模式，优化HTML文档操作、事件处理、动画设计和Ajax交互。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a89598b-bbc1-45a0-bad7-cdb483d47297",
   "metadata": {},
   "source": [
    "jquery核心用法\n",
    "- \\$(\"css选择器\")选出的元素是jquery对象，而不是普通的dom对象\n",
    "- \\$(\"HTML元素\")可以直接将字符串描述的html元素创建出来，构成一个jQuery对象。\n",
    "- \\\\$(document).ready(function(){…….});可以设定在页面加载完成之后执行的函数，也可以简写成\\$(function(){…..})；"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bcc9bd3-26c1-464d-b837-beeef70d96de",
   "metadata": {},
   "source": [
    "## 动态示例"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb7649fe-f72e-4e1b-982e-13e88ce47613",
   "metadata": {},
   "source": [
    "### 动态Echarts代码"
   ]
  },
  {
   "cell_type": "raw",
   "id": "e8705bcc-bf20-4785-b014-47211d551600",
   "metadata": {},
   "source": [
    "var option = {\n",
    "     xAxis: {\n",
    "        type: 'category',\n",
    "        boundaryGap: false,\n",
    "        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n",
    "    },\n",
    "    yAxis: {\n",
    "        type: 'value'\n",
    "    },\n",
    "    series: [{\n",
    "        data: [820, 932, 901, 934, 1290, 1330, 1320],\n",
    "        type: 'line',\n",
    "        areaStyle: {}\n",
    "    }]\n",
    "};\n",
    "window.onload=function(){\n",
    "    //1.初始化echarts\n",
    "    var myChart = echarts.init(document.getElementById(\"div_1\"))\t\t\t\t\n",
    "    //2.加载初始数据\n",
    "    myChart.setOption(option)\n",
    "    //3.动态加载数据\n",
    "    window.setInterval(function(){\n",
    "        $.get(\"http://127.0.0.1:5000/echarts\",function(datax){\n",
    "            console.log(datax)\n",
    "            console.log(eval(datax))\n",
    "            option.series[0].data = eval(datax)\n",
    "            myChart.setOption(option)\n",
    "        })\n",
    "    }, 500);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0095892-0a94-4af4-91c2-b047de86ab16",
   "metadata": {},
   "source": [
    "#### jquery的GET请求"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba7b66e2-f4f6-4d05-9fcd-289dd74fe276",
   "metadata": {},
   "source": [
    "Ajax 即“Asynchronous Javascript And XML”（异步 JavaScript 和 XML），是指一种创建交互式、快速动态网页应用的网页开发技术，无需重新加载整个网页的情况下，能够更新部分网页的技术。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58442f92-8993-4243-a9f0-bcd0ed14e129",
   "metadata": {},
   "source": [
    "简短地说，在不重载整个网页的情况下，AJAX 通过后台加载数据，并在网页上进行显示"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ae1e50f-ff18-44f4-982f-d762acfc1027",
   "metadata": {},
   "source": [
    "jQuery AJAX get() 和 post() 方法：https://www.w3school.com.cn/jquery/jquery_ajax_get_post.asp  \n",
    "HTTP请求（面试常考）：https://www.w3school.com.cn/tags/html_ref_httpmethods.asp"
   ]
  },
  {
   "cell_type": "raw",
   "id": "e59469cb-f868-46b1-ab2d-f06451e65516",
   "metadata": {},
   "source": [
    "$.get(\"http://127.0.0.1:5000/echarts\",function(datax){\n",
    "    console.log(datax)\n",
    "    console.log(eval(datax))\n",
    "    option.series[0].data = eval(datax)\n",
    "    myChart.setOption(option)\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4cbb4ec9-8d04-4309-9e9e-b2a4a48d9173",
   "metadata": {},
   "source": [
    "#### eval函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f107f04e-1142-4350-bb95-ec449da28015",
   "metadata": {},
   "source": [
    "将字符串看成可执行的指令，python/js等语言的eval意义类似，但是要慎用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "56bb891c-3808-4e1c-b5b4-e93c5bbb1e0e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'[76, 61, 40, 38, 96, 35, 99]'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res = str([random.randint(1,100) for i in range(7)])\n",
    "res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "64ccd973-4301-4659-8b3a-d0e763f47154",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[9, 82, 3, 87, 72, 73, 54]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eval(res)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "d6c4cacb-0530-4f42-8cdf-43b061f69b80",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "2ea2eb44-7252-4fba-b335-f58a9eb478f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "eval('os.mkdir(\"eval入侵\")')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea68cb72-ca89-4898-992c-6abe270f2132",
   "metadata": {
    "tags": []
   },
   "source": [
    "#### 定时请求"
   ]
  },
  {
   "cell_type": "raw",
   "id": "5f85724f-0d09-4368-af4b-83380aa15e59",
   "metadata": {},
   "source": [
    "window.setInterval(xxx, 500);"
   ]
  },
  {
   "cell_type": "raw",
   "id": "703e4f50-0577-48e2-966f-b07ecfbd3cf7",
   "metadata": {},
   "source": [
    "window.setInterval(function(){\n",
    "    $.get(\"http://127.0.0.1:5000/echarts\",function(datax){\n",
    "        console.log(datax)\n",
    "        console.log(eval(datax))\n",
    "        option.series[0].data = eval(datax)\n",
    "        myChart.setOption(option)\n",
    "    })\n",
    "}, 500);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02bd2994-f51f-471a-b8eb-aa1a696b2833",
   "metadata": {},
   "source": [
    "### Flask动态代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6101a8f-6fa0-4efc-9324-2200dd76ea1e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from flask import Flask\n",
    "import random\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to My Watchlist!'\n",
    "\n",
    "@app.route('/echarts')\n",
    "def getEcharts():\n",
    "    res = str([random.randint(1,100) for i in range(7)])\n",
    "    return res\n",
    "\n",
    "app.run(host='0.0.0.0', port=5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b847a1e1-6664-46d3-a388-a94dd56e3fec",
   "metadata": {},
   "source": [
    "#### Chrome调试工具"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "525030cc-0c2c-4e27-a1f9-ad847f242502",
   "metadata": {},
   "source": [
    "Chrome调试工具介绍：https://www.jianshu.com/p/92c172e77e27"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e02ce13-19b8-4e83-8c95-c228b836f275",
   "metadata": {},
   "source": [
    "#### 跨域策略"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be2df090-7e24-4947-9c43-ba493a50b1ae",
   "metadata": {},
   "source": [
    "浏览器的**同源策略**（Same origin policy）是一种约定，所谓同源（即指在同一个域）就是两个页面具有相同的协议（protocol），主机（host）和端口号（port）。\n",
    "\n",
    "它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的，浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1b4fa4e-9ac5-4699-aa84-fe06c5389808",
   "metadata": {},
   "outputs": [],
   "source": [
    "from flask import Flask\n",
    "from flask_cors import *\n",
    "import random\n",
    "app = Flask(__name__)\n",
    "CORS(app, supports_credentials=True)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to My Watchlist!'\n",
    "\n",
    "@app.route('/echarts')\n",
    "def getEcharts():\n",
    "    res = str([random.randint(1,100) for i in range(7)])\n",
    "    return res\n",
    "\n",
    "app.run(host='0.0.0.0', port=5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b572273-2770-4817-88f8-81ca672fbf2e",
   "metadata": {},
   "source": [
    "## K线图动态示例"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e675b270-8d61-4a4b-9da5-010eb836fe69",
   "metadata": {},
   "source": [
    "matplotlib有个示例区，echarts之前也有，但ECharts MakeAPie（Gallery）2 月 15 号开始暂停服务"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2172af5f-f1de-4af5-b56a-6ed8528cc148",
   "metadata": {},
   "source": [
    "如何看待 ECharts MakeAPie（Gallery）2 月 15 号开始暂停服务？：https://www.zhihu.com/question/513511544"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efc5678d-268e-4773-a7ae-c461392b91f8",
   "metadata": {},
   "source": [
    "可能未来这些网站也没了，或者你们找的代码存在差异，所以以我视频中的资料为准，可以去github下载"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "294556d8-6a83-41cc-97ac-2ffef06bbce2",
   "metadata": {},
   "source": [
    "### 固定传值"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "963dc467-9c5a-4e5b-85d9-deaf62dfb39d",
   "metadata": {},
   "source": [
    "前端代码主要关注：\n",
    "- 数据情况\n",
    "- 请求接口"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "565a9538-9321-4589-b045-986ed380dc54",
   "metadata": {},
   "source": [
    "#### 数据情况"
   ]
  },
  {
   "cell_type": "raw",
   "id": "10008956-4b26-42bb-b51b-bd52adcd0a7f",
   "metadata": {},
   "source": [
    "$.ajaxSettings.async = false;\n",
    "$.get(\"http://127.0.0.1:5000/stock?ID=600000\",function(datax){\n",
    "\trawData = eval(datax).reverse()\n",
    "});\n",
    "$.ajaxSettings.async = true;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "25cd78d1-5351-4337-a04f-bca195a90ad6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "本接口即将停止更新，请尽快使用Pro版接口：https://tushare.pro/document/2\n"
     ]
    }
   ],
   "source": [
    "import tushare as ts\n",
    "stock = ts.get_hist_data('600000', start='2019-01-01')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "e3f6b96b-b8b7-44cf-b25a-c7be34701322",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0      None\n",
       "1      None\n",
       "2      None\n",
       "3      None\n",
       "4      None\n",
       "       ... \n",
       "600    None\n",
       "601    None\n",
       "602    None\n",
       "603    None\n",
       "604    None\n",
       "Length: 605, dtype: object"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = []\n",
    "stock.reset_index().apply(lambda x: data.append([str(x['date']), str(x['open']), str(x['close']), \n",
    "                                                 str(x['price_change']), str(x['p_change']), str(x['low']), \n",
    "                                                 str(x['high'])]),  axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d675e241-11eb-42ce-b4bf-2fb57d8d50fe",
   "metadata": {},
   "source": [
    "#### 时间构建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2f403399-ec8d-4422-825e-e0ca999be010",
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "ae576a47-ea74-42b2-892e-5311bd6faa55",
   "metadata": {},
   "outputs": [],
   "source": [
    "now = datetime.datetime.now()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "49baddf7-a249-4a7b-a030-6a4b5531c8e7",
   "metadata": {},
   "outputs": [],
   "source": [
    "now_str = now.strftime('%Y-%m-%d')\n",
    "last_str = datetime.datetime(year=now.year-1, month=now.month, day=now.day).strftime('%Y-%m-%d')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5db70aca-c86a-44b9-9632-05cb20ad44ee",
   "metadata": {},
   "source": [
    "#### GET传值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "1cec202e-5eb2-40bd-875a-70604d5abdae",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app '__main__' (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n",
      "2022-06-05 16:42:43,249 - werkzeug - INFO -  * Running on all addresses (0.0.0.0)\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://127.0.0.1:5000\n",
      " * Running on http://192.168.1.8:5000 (Press CTRL+C to quit)\n",
      "本接口即将停止更新，请尽快使用Pro版接口：https://tushare.pro/document/2\n",
      "耗时 9.21683955192566 秒\n",
      "2022-06-05 16:43:15,218 - werkzeug - INFO - 127.0.0.1 - - [05/Jun/2022 16:43:15] \"GET /stock?ID=600000 HTTP/1.1\" 200 -\n",
      "本接口即将停止更新，请尽快使用Pro版接口：https://tushare.pro/document/2\n",
      "耗时 9.19838833808899 秒\n",
      "2022-06-05 16:43:38,215 - werkzeug - INFO - 127.0.0.1 - - [05/Jun/2022 16:43:38] \"GET /stock?ID=600723 HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "import time \n",
    "import datetime\n",
    "import tushare as ts\n",
    "from flask import Flask\n",
    "from flask_cors import *\n",
    "from flask import request\n",
    "app = Flask(__name__)\n",
    "CORS(app, supports_credentials=True)\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to My Watchlist!'\n",
    "\n",
    "@app.route('/stock', methods=[\"GET\"])\n",
    "def getStock():\n",
    "    begin = time.time()\n",
    "    \n",
    "    ## 获取时间\n",
    "    now = datetime.datetime.now()\n",
    "    now_str = now.strftime('%Y-%m-%d')\n",
    "    last_str = datetime.datetime(year=now.year-1, month=now.month, day=now.day).strftime('%Y-%m-%d')\n",
    "    ## 接受传参\n",
    "    ID = request.args.get(\"ID\")\n",
    "    hist = ts.get_hist_data(ID, start=last_str)\n",
    "    data = []\n",
    "    hist.reset_index().apply(lambda x: data.append([str(x['date']), str(x['open']), str(x['close']), \n",
    "                                                     str(x['price_change']), str(x['p_change']), str(x['low']), \n",
    "                                                     str(x['high'])]),  axis=1)\n",
    "    end = time.time()\n",
    "    print('耗时', end-begin, '秒')\n",
    "    return str(data)\n",
    "\n",
    "app.run(host='0.0.0.0', port=5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55c064b2-1093-45ed-a51f-748431071b46",
   "metadata": {},
   "source": [
    "### 表单传值"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "033b3389-e980-4f6e-b6d7-cf912405700e",
   "metadata": {},
   "source": [
    "三种请求本质上都在调用\\$.get：\n",
    "- 定时请求，window.setInterval(xxx, 500);\n",
    "- 请求一次\n",
    "- 绑定事件"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f89821bf-6302-40fc-bf5d-f7dc0f45fea3",
   "metadata": {},
   "source": [
    "HTML table 标签 :https://www.w3school.com.cn/tags/tag_table.asp  \n",
    "HTML button 标签:https://www.w3school.com.cn/tags/tag_button.asp"
   ]
  },
  {
   "cell_type": "raw",
   "id": "37d37789-aec3-4116-8187-c793db6ace54",
   "metadata": {},
   "source": [
    "<table align=\"center\" bordercolor=\"#000000\" border=\"2\" cellspacing=\"0\" cellpadding=\"5\" bgcolor=\"white\"> \n",
    "    <caption><h1><font color=\"red\">股票K线查询系统</font></h1></caption>\n",
    "    <tr>\n",
    "        <td>股票代码：</td>\n",
    "        <td><input type=\"text\" id=\"ID\" name=\"ID\" placeholder=\"请输入股票代码\"></td>\n",
    "        <td><button type=\"submit\" onclick=\"resetData()\" name=\"sub\" >提交</button></td>\n",
    "    </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad1a03ae-29bb-4cef-b43c-556ab31197cd",
   "metadata": {},
   "source": [
    "只用改前端！后端不要动！"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8634eafd-5339-40eb-9c13-bb5654719215",
   "metadata": {},
   "source": [
    "### 缓存添加"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1cc9f2a-1f8d-4d1c-96f7-6d9c313b8c81",
   "metadata": {},
   "source": [
    "每次请求都需要到tushare获取1年的数据，平均要耗时9秒"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f7b3cf7-ea2a-4952-b011-f39c12a9f0e8",
   "metadata": {},
   "source": [
    "#### 本地简单缓存"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "a5b81af9-a12a-4d58-aa31-1f909c8d2e8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "0ed7490b-d913-4f7e-865a-56eba7952591",
   "metadata": {},
   "outputs": [],
   "source": [
    "cache_folder = 'data'\n",
    "if not os.path.exists(cache_folder):\n",
    "    os.mkdir(cache_folder)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "b7059b40-c0aa-4cce-b48e-027cf5e9bec8",
   "metadata": {},
   "outputs": [],
   "source": [
    "ID = '600000'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "a4fc1dc7-99f2-4bd3-9b59-1e022bb3f97e",
   "metadata": {},
   "outputs": [],
   "source": [
    "now = datetime.datetime.now()\n",
    "now_str = now.strftime('%Y-%m-%d')\n",
    "last_str = datetime.datetime(year=now.year-1, month=now.month, day=now.day).strftime('%Y-%m-%d')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "638b1d65-a59a-4f7a-8395-39de9f0aa6d7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "本接口即将停止更新，请尽快使用Pro版接口：https://tushare.pro/document/2\n"
     ]
    }
   ],
   "source": [
    "hist = ts.get_hist_data(ID, start=last_str)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "30b5a798-2ee2-41c5-a897-c49b67c96949",
   "metadata": {},
   "outputs": [],
   "source": [
    "file_path = os.path.join(cache_folder, f'{ID}.csv')\n",
    "hist.to_csv(file_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "b76a3eb4-bf89-4171-a1b3-0037a72639f7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "os.path.exists(file_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "9935b14f-eb91-4865-ba23-d403fd09f37e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "cache_data = pd.read_csv(file_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "2f09fbdd-5d5d-4bc8-a5bf-168854107987",
   "metadata": {},
   "outputs": [],
   "source": [
    "cache_data = cache_data.set_index('date')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "d8c66238-f414-4130-91d6-032c38ea7048",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>close</th>\n",
       "      <th>low</th>\n",
       "      <th>volume</th>\n",
       "      <th>price_change</th>\n",
       "      <th>p_change</th>\n",
       "      <th>ma5</th>\n",
       "      <th>ma10</th>\n",
       "      <th>ma20</th>\n",
       "      <th>v_ma5</th>\n",
       "      <th>v_ma10</th>\n",
       "      <th>v_ma20</th>\n",
       "      <th>turnover</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2022-06-02</th>\n",
       "      <td>7.89</td>\n",
       "      <td>7.91</td>\n",
       "      <td>7.89</td>\n",
       "      <td>7.87</td>\n",
       "      <td>189311.16</td>\n",
       "      <td>-0.02</td>\n",
       "      <td>-0.25</td>\n",
       "      <td>7.924</td>\n",
       "      <td>7.927</td>\n",
       "      <td>7.921</td>\n",
       "      <td>273071.07</td>\n",
       "      <td>265196.15</td>\n",
       "      <td>254951.84</td>\n",
       "      <td>0.06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2022-06-01</th>\n",
       "      <td>7.94</td>\n",
       "      <td>7.94</td>\n",
       "      <td>7.91</td>\n",
       "      <td>7.89</td>\n",
       "      <td>184019.41</td>\n",
       "      <td>-0.03</td>\n",
       "      <td>-0.38</td>\n",
       "      <td>7.926</td>\n",
       "      <td>7.929</td>\n",
       "      <td>7.926</td>\n",
       "      <td>282012.02</td>\n",
       "      <td>266169.22</td>\n",
       "      <td>260052.86</td>\n",
       "      <td>0.06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2022-05-31</th>\n",
       "      <td>7.90</td>\n",
       "      <td>7.98</td>\n",
       "      <td>7.94</td>\n",
       "      <td>7.88</td>\n",
       "      <td>317508.84</td>\n",
       "      <td>0.06</td>\n",
       "      <td>0.76</td>\n",
       "      <td>7.920</td>\n",
       "      <td>7.933</td>\n",
       "      <td>7.932</td>\n",
       "      <td>287214.86</td>\n",
       "      <td>267231.19</td>\n",
       "      <td>273108.31</td>\n",
       "      <td>0.11</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2022-05-30</th>\n",
       "      <td>8.01</td>\n",
       "      <td>8.02</td>\n",
       "      <td>7.88</td>\n",
       "      <td>7.87</td>\n",
       "      <td>356962.56</td>\n",
       "      <td>-0.12</td>\n",
       "      <td>-1.50</td>\n",
       "      <td>7.908</td>\n",
       "      <td>7.941</td>\n",
       "      <td>7.935</td>\n",
       "      <td>275770.12</td>\n",
       "      <td>254194.50</td>\n",
       "      <td>279820.45</td>\n",
       "      <td>0.12</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2022-05-27</th>\n",
       "      <td>7.92</td>\n",
       "      <td>8.01</td>\n",
       "      <td>8.00</td>\n",
       "      <td>7.88</td>\n",
       "      <td>317553.38</td>\n",
       "      <td>0.10</td>\n",
       "      <td>1.27</td>\n",
       "      <td>7.922</td>\n",
       "      <td>7.950</td>\n",
       "      <td>7.932</td>\n",
       "      <td>255432.75</td>\n",
       "      <td>239489.07</td>\n",
       "      <td>281316.63</td>\n",
       "      <td>0.11</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-11</th>\n",
       "      <td>10.24</td>\n",
       "      <td>10.28</td>\n",
       "      <td>10.17</td>\n",
       "      <td>10.11</td>\n",
       "      <td>580302.50</td>\n",
       "      <td>-0.06</td>\n",
       "      <td>-0.59</td>\n",
       "      <td>10.230</td>\n",
       "      <td>10.229</td>\n",
       "      <td>10.225</td>\n",
       "      <td>493900.58</td>\n",
       "      <td>485214.22</td>\n",
       "      <td>442268.52</td>\n",
       "      <td>0.20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-10</th>\n",
       "      <td>10.21</td>\n",
       "      <td>10.31</td>\n",
       "      <td>10.23</td>\n",
       "      <td>10.20</td>\n",
       "      <td>456854.31</td>\n",
       "      <td>0.02</td>\n",
       "      <td>0.20</td>\n",
       "      <td>10.242</td>\n",
       "      <td>10.247</td>\n",
       "      <td>10.226</td>\n",
       "      <td>519944.94</td>\n",
       "      <td>461777.26</td>\n",
       "      <td>437094.09</td>\n",
       "      <td>0.16</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-09</th>\n",
       "      <td>10.29</td>\n",
       "      <td>10.35</td>\n",
       "      <td>10.21</td>\n",
       "      <td>10.21</td>\n",
       "      <td>560950.94</td>\n",
       "      <td>-0.10</td>\n",
       "      <td>-0.97</td>\n",
       "      <td>10.242</td>\n",
       "      <td>10.253</td>\n",
       "      <td>10.219</td>\n",
       "      <td>533063.90</td>\n",
       "      <td>468155.16</td>\n",
       "      <td>437857.66</td>\n",
       "      <td>0.19</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-08</th>\n",
       "      <td>10.24</td>\n",
       "      <td>10.33</td>\n",
       "      <td>10.31</td>\n",
       "      <td>10.18</td>\n",
       "      <td>508381.16</td>\n",
       "      <td>0.08</td>\n",
       "      <td>0.78</td>\n",
       "      <td>10.244</td>\n",
       "      <td>10.267</td>\n",
       "      <td>10.214</td>\n",
       "      <td>492534.67</td>\n",
       "      <td>467044.88</td>\n",
       "      <td>435816.16</td>\n",
       "      <td>0.17</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-07</th>\n",
       "      <td>10.26</td>\n",
       "      <td>10.27</td>\n",
       "      <td>10.23</td>\n",
       "      <td>10.20</td>\n",
       "      <td>363014.00</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "      <td>10.220</td>\n",
       "      <td>10.268</td>\n",
       "      <td>10.201</td>\n",
       "      <td>474619.20</td>\n",
       "      <td>491624.33</td>\n",
       "      <td>431563.99</td>\n",
       "      <td>0.12</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>240 rows × 14 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "             open   high  close    low     volume  price_change  p_change  \\\n",
       "date                                                                        \n",
       "2022-06-02   7.89   7.91   7.89   7.87  189311.16         -0.02     -0.25   \n",
       "2022-06-01   7.94   7.94   7.91   7.89  184019.41         -0.03     -0.38   \n",
       "2022-05-31   7.90   7.98   7.94   7.88  317508.84          0.06      0.76   \n",
       "2022-05-30   8.01   8.02   7.88   7.87  356962.56         -0.12     -1.50   \n",
       "2022-05-27   7.92   8.01   8.00   7.88  317553.38          0.10      1.27   \n",
       "...           ...    ...    ...    ...        ...           ...       ...   \n",
       "2021-06-11  10.24  10.28  10.17  10.11  580302.50         -0.06     -0.59   \n",
       "2021-06-10  10.21  10.31  10.23  10.20  456854.31          0.02      0.20   \n",
       "2021-06-09  10.29  10.35  10.21  10.21  560950.94         -0.10     -0.97   \n",
       "2021-06-08  10.24  10.33  10.31  10.18  508381.16          0.08      0.78   \n",
       "2021-06-07  10.26  10.27  10.23  10.20  363014.00          0.00      0.00   \n",
       "\n",
       "               ma5    ma10    ma20      v_ma5     v_ma10     v_ma20  turnover  \n",
       "date                                                                           \n",
       "2022-06-02   7.924   7.927   7.921  273071.07  265196.15  254951.84      0.06  \n",
       "2022-06-01   7.926   7.929   7.926  282012.02  266169.22  260052.86      0.06  \n",
       "2022-05-31   7.920   7.933   7.932  287214.86  267231.19  273108.31      0.11  \n",
       "2022-05-30   7.908   7.941   7.935  275770.12  254194.50  279820.45      0.12  \n",
       "2022-05-27   7.922   7.950   7.932  255432.75  239489.07  281316.63      0.11  \n",
       "...            ...     ...     ...        ...        ...        ...       ...  \n",
       "2021-06-11  10.230  10.229  10.225  493900.58  485214.22  442268.52      0.20  \n",
       "2021-06-10  10.242  10.247  10.226  519944.94  461777.26  437094.09      0.16  \n",
       "2021-06-09  10.242  10.253  10.219  533063.90  468155.16  437857.66      0.19  \n",
       "2021-06-08  10.244  10.267  10.214  492534.67  467044.88  435816.16      0.17  \n",
       "2021-06-07  10.220  10.268  10.201  474619.20  491624.33  431563.99      0.12  \n",
       "\n",
       "[240 rows x 14 columns]"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res = cache_data[(cache_data.index >= last_str) & (cache_data.index <= now_str)]\n",
    "res"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "974f9c15-98b8-411b-b980-abc2aa4460bf",
   "metadata": {},
   "source": [
    "#### 缓存函数封装"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "22e03031-6266-4ce7-9803-d60ef2266737",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, datetime\n",
    "import pandas as pd\n",
    "import tushare as ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "532e436b-73e8-42ce-aefc-285514bf6793",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_data(ID, cache_folder='data'):\n",
    "    ## 判断路径是否存在\n",
    "    if not os.path.exists(cache_folder):\n",
    "        os.mkdir(cache_folder)\n",
    "    ## 生成当前系统时间\n",
    "    now = datetime.datetime.now()\n",
    "    now_str = now.strftime('%Y-%m-%d')\n",
    "    last_str = datetime.datetime(year=now.year-1, month=now.month, day=now.day).strftime('%Y-%m-%d')\n",
    "    ## 判断文件是否存在\n",
    "    file_path = os.path.join(cache_folder, f'{ID}.csv')\n",
    "    if os.path.exists(file_path): # 存在即读取\n",
    "        cache_data = pd.read_csv(file_path)\n",
    "        cache_data = cache_data.set_index('date') # 设置索引\n",
    "        cache_data[(cache_data.index >= last_str) & (cache_data.index <= now_str)] # 取出时间间隔\n",
    "    else: # 不存在则获取并缓存\n",
    "        # 此处为了简单，还是从前一年获取，理论上最好全部后缓存\n",
    "        cache_data = ts.get_hist_data(ID, start=last_str) # 获取时间间隔数据\n",
    "        cache_data.to_csv(file_path)\n",
    "    return cache_data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb1e0666-dfc8-4185-b5b7-f63a5ce14d5a",
   "metadata": {},
   "source": [
    "#### 测试缓存函数运行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bb843628-f85b-4aab-9c3f-53bd437297a9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: total: 0 ns\n",
      "Wall time: 2.99 ms\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>close</th>\n",
       "      <th>low</th>\n",
       "      <th>volume</th>\n",
       "      <th>price_change</th>\n",
       "      <th>p_change</th>\n",
       "      <th>ma5</th>\n",
       "      <th>ma10</th>\n",
       "      <th>ma20</th>\n",
       "      <th>v_ma5</th>\n",
       "      <th>v_ma10</th>\n",
       "      <th>v_ma20</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2021-09-15</th>\n",
       "      <td>9.03</td>\n",
       "      <td>9.18</td>\n",
       "      <td>8.93</td>\n",
       "      <td>8.79</td>\n",
       "      <td>114958.65</td>\n",
       "      <td>-0.11</td>\n",
       "      <td>-1.22</td>\n",
       "      <td>9.162</td>\n",
       "      <td>9.243</td>\n",
       "      <td>8.689</td>\n",
       "      <td>79255.99</td>\n",
       "      <td>101038.43</td>\n",
       "      <td>75685.16</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-09-14</th>\n",
       "      <td>9.20</td>\n",
       "      <td>9.32</td>\n",
       "      <td>9.04</td>\n",
       "      <td>8.98</td>\n",
       "      <td>65753.11</td>\n",
       "      <td>-0.17</td>\n",
       "      <td>-1.85</td>\n",
       "      <td>9.232</td>\n",
       "      <td>9.212</td>\n",
       "      <td>8.649</td>\n",
       "      <td>85384.42</td>\n",
       "      <td>97062.06</td>\n",
       "      <td>71732.88</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-09-13</th>\n",
       "      <td>9.36</td>\n",
       "      <td>9.40</td>\n",
       "      <td>9.21</td>\n",
       "      <td>9.19</td>\n",
       "      <td>73043.20</td>\n",
       "      <td>-0.14</td>\n",
       "      <td>-1.50</td>\n",
       "      <td>9.294</td>\n",
       "      <td>9.160</td>\n",
       "      <td>8.600</td>\n",
       "      <td>87196.61</td>\n",
       "      <td>96815.68</td>\n",
       "      <td>71100.37</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-09-10</th>\n",
       "      <td>9.27</td>\n",
       "      <td>9.44</td>\n",
       "      <td>9.35</td>\n",
       "      <td>9.26</td>\n",
       "      <td>82464.65</td>\n",
       "      <td>0.07</td>\n",
       "      <td>0.75</td>\n",
       "      <td>9.334</td>\n",
       "      <td>9.085</td>\n",
       "      <td>8.547</td>\n",
       "      <td>91732.07</td>\n",
       "      <td>98327.70</td>\n",
       "      <td>69743.13</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-09-09</th>\n",
       "      <td>9.26</td>\n",
       "      <td>9.40</td>\n",
       "      <td>9.28</td>\n",
       "      <td>9.20</td>\n",
       "      <td>60060.35</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "      <td>9.348</td>\n",
       "      <td>8.966</td>\n",
       "      <td>8.488</td>\n",
       "      <td>107479.48</td>\n",
       "      <td>95623.92</td>\n",
       "      <td>71573.78</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-11</th>\n",
       "      <td>8.80</td>\n",
       "      <td>8.95</td>\n",
       "      <td>8.69</td>\n",
       "      <td>8.64</td>\n",
       "      <td>34435.00</td>\n",
       "      <td>-0.12</td>\n",
       "      <td>-1.36</td>\n",
       "      <td>8.948</td>\n",
       "      <td>9.108</td>\n",
       "      <td>8.829</td>\n",
       "      <td>43056.60</td>\n",
       "      <td>67645.53</td>\n",
       "      <td>65744.10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-10</th>\n",
       "      <td>8.95</td>\n",
       "      <td>9.04</td>\n",
       "      <td>8.81</td>\n",
       "      <td>8.79</td>\n",
       "      <td>40659.70</td>\n",
       "      <td>-0.16</td>\n",
       "      <td>-1.78</td>\n",
       "      <td>9.058</td>\n",
       "      <td>9.106</td>\n",
       "      <td>8.798</td>\n",
       "      <td>48326.79</td>\n",
       "      <td>67921.72</td>\n",
       "      <td>65401.20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-09</th>\n",
       "      <td>8.95</td>\n",
       "      <td>9.06</td>\n",
       "      <td>8.97</td>\n",
       "      <td>8.89</td>\n",
       "      <td>38522.92</td>\n",
       "      <td>-0.05</td>\n",
       "      <td>-0.55</td>\n",
       "      <td>9.164</td>\n",
       "      <td>9.105</td>\n",
       "      <td>8.760</td>\n",
       "      <td>50985.28</td>\n",
       "      <td>68783.52</td>\n",
       "      <td>65184.34</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-08</th>\n",
       "      <td>9.24</td>\n",
       "      <td>9.25</td>\n",
       "      <td>9.02</td>\n",
       "      <td>8.97</td>\n",
       "      <td>64508.28</td>\n",
       "      <td>-0.23</td>\n",
       "      <td>-2.49</td>\n",
       "      <td>9.230</td>\n",
       "      <td>9.096</td>\n",
       "      <td>8.716</td>\n",
       "      <td>56234.32</td>\n",
       "      <td>69764.28</td>\n",
       "      <td>64813.64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-06-07</th>\n",
       "      <td>9.20</td>\n",
       "      <td>9.35</td>\n",
       "      <td>9.25</td>\n",
       "      <td>9.19</td>\n",
       "      <td>37157.08</td>\n",
       "      <td>0.01</td>\n",
       "      <td>0.11</td>\n",
       "      <td>9.302</td>\n",
       "      <td>9.076</td>\n",
       "      <td>8.670</td>\n",
       "      <td>68282.88</td>\n",
       "      <td>68329.57</td>\n",
       "      <td>63049.53</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>71 rows × 13 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            open  high  close   low     volume  price_change  p_change    ma5  \\\n",
       "date                                                                            \n",
       "2021-09-15  9.03  9.18   8.93  8.79  114958.65         -0.11     -1.22  9.162   \n",
       "2021-09-14  9.20  9.32   9.04  8.98   65753.11         -0.17     -1.85  9.232   \n",
       "2021-09-13  9.36  9.40   9.21  9.19   73043.20         -0.14     -1.50  9.294   \n",
       "2021-09-10  9.27  9.44   9.35  9.26   82464.65          0.07      0.75  9.334   \n",
       "2021-09-09  9.26  9.40   9.28  9.20   60060.35          0.00      0.00  9.348   \n",
       "...          ...   ...    ...   ...        ...           ...       ...    ...   \n",
       "2021-06-11  8.80  8.95   8.69  8.64   34435.00         -0.12     -1.36  8.948   \n",
       "2021-06-10  8.95  9.04   8.81  8.79   40659.70         -0.16     -1.78  9.058   \n",
       "2021-06-09  8.95  9.06   8.97  8.89   38522.92         -0.05     -0.55  9.164   \n",
       "2021-06-08  9.24  9.25   9.02  8.97   64508.28         -0.23     -2.49  9.230   \n",
       "2021-06-07  9.20  9.35   9.25  9.19   37157.08          0.01      0.11  9.302   \n",
       "\n",
       "             ma10   ma20      v_ma5     v_ma10    v_ma20  \n",
       "date                                                      \n",
       "2021-09-15  9.243  8.689   79255.99  101038.43  75685.16  \n",
       "2021-09-14  9.212  8.649   85384.42   97062.06  71732.88  \n",
       "2021-09-13  9.160  8.600   87196.61   96815.68  71100.37  \n",
       "2021-09-10  9.085  8.547   91732.07   98327.70  69743.13  \n",
       "2021-09-09  8.966  8.488  107479.48   95623.92  71573.78  \n",
       "...           ...    ...        ...        ...       ...  \n",
       "2021-06-11  9.108  8.829   43056.60   67645.53  65744.10  \n",
       "2021-06-10  9.106  8.798   48326.79   67921.72  65401.20  \n",
       "2021-06-09  9.105  8.760   50985.28   68783.52  65184.34  \n",
       "2021-06-08  9.096  8.716   56234.32   69764.28  64813.64  \n",
       "2021-06-07  9.076  8.670   68282.88   68329.57  63049.53  \n",
       "\n",
       "[71 rows x 13 columns]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "get_data('600723')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d50d9076-0285-4289-bdee-f3da2541ccb1",
   "metadata": {},
   "source": [
    "### 缓存传值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "6565de25-47e3-4e29-97e4-39593eef78d6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app '__main__' (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n",
      "2022-06-05 17:08:43,596 - werkzeug - INFO -  * Running on all addresses (0.0.0.0)\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://127.0.0.1:5000\n",
      " * Running on http://192.168.1.8:5000 (Press CTRL+C to quit)\n",
      "耗时 0.006979942321777344 秒\n",
      "2022-06-05 17:08:47,908 - werkzeug - INFO - 127.0.0.1 - - [05/Jun/2022 17:08:47] \"GET /stock?ID=600723 HTTP/1.1\" 200 -\n",
      "本接口即将停止更新，请尽快使用Pro版接口：https://tushare.pro/document/2\n",
      "耗时 9.233950138092041 秒\n",
      "2022-06-05 17:09:03,451 - werkzeug - INFO - 127.0.0.1 - - [05/Jun/2022 17:09:03] \"GET /stock?ID=600724 HTTP/1.1\" 200 -\n",
      "耗时 0.005983114242553711 秒\n",
      "2022-06-05 17:09:11,323 - werkzeug - INFO - 127.0.0.1 - - [05/Jun/2022 17:09:11] \"GET /stock?ID=600723 HTTP/1.1\" 200 -\n",
      "2022-06-05 17:26:14,805 - werkzeug - INFO - 192.168.1.12 - - [05/Jun/2022 17:26:14] \"\u001b[33mGET /echarts HTTP/1.1\u001b[0m\" 404 -\n",
      "2022-06-05 17:26:14,966 - werkzeug - INFO - 192.168.1.12 - - [05/Jun/2022 17:26:14] \"\u001b[33mGET /favicon.ico HTTP/1.1\u001b[0m\" 404 -\n",
      "本接口即将停止更新，请尽快使用Pro版接口：https://tushare.pro/document/2\n",
      "2022-06-05 17:26:27,502 - __main__ - ERROR - Exception on /stock [GET]\n",
      "Traceback (most recent call last):\n",
      "  File \"F:\\conda\\envs\\afan_test\\lib\\site-packages\\flask\\app.py\", line 2077, in wsgi_app\n",
      "    response = self.full_dispatch_request()\n",
      "  File \"F:\\conda\\envs\\afan_test\\lib\\site-packages\\flask\\app.py\", line 1525, in full_dispatch_request\n",
      "    rv = self.handle_user_exception(e)\n",
      "  File \"F:\\conda\\envs\\afan_test\\lib\\site-packages\\flask_cors\\extension.py\", line 161, in wrapped_function\n",
      "    return cors_after_request(app.make_response(f(*args, **kwargs)))\n",
      "  File \"F:\\conda\\envs\\afan_test\\lib\\site-packages\\flask\\app.py\", line 1523, in full_dispatch_request\n",
      "    rv = self.dispatch_request()\n",
      "  File \"F:\\conda\\envs\\afan_test\\lib\\site-packages\\flask\\app.py\", line 1509, in dispatch_request\n",
      "    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n",
      "  File \"C:\\Users\\Administrator\\AppData\\Local\\Temp\\ipykernel_29144\\4240308972.py\", line 45, in getStock\n",
      "    hist = get_data(ID)\n",
      "  File \"C:\\Users\\Administrator\\AppData\\Local\\Temp\\ipykernel_29144\\4240308972.py\", line 27, in get_data\n",
      "    cache_data = ts.get_hist_data(ID, start=last_str) # 获取时间间隔数据\n",
      "  File \"F:\\conda\\envs\\afan_test\\lib\\site-packages\\tushare\\stock\\trading.py\", line 60, in get_hist_data\n",
      "    symbol = ct._code_to_symbol(code)\n",
      "  File \"F:\\conda\\envs\\afan_test\\lib\\site-packages\\tushare\\stock\\cons.py\", line 415, in _code_to_symbol\n",
      "    if len(code) != 6 :\n",
      "TypeError: object of type 'NoneType' has no len()\n",
      "2022-06-05 17:26:27,508 - werkzeug - INFO - 192.168.1.12 - - [05/Jun/2022 17:26:27] \"\u001b[35m\u001b[1mGET /stock HTTP/1.1\u001b[0m\" 500 -\n",
      "2022-06-05 17:26:27,814 - werkzeug - INFO - 192.168.1.12 - - [05/Jun/2022 17:26:27] \"\u001b[33mGET /favicon.ico HTTP/1.1\u001b[0m\" 404 -\n"
     ]
    }
   ],
   "source": [
    "import time \n",
    "import os, datetime\n",
    "import pandas as pd\n",
    "import tushare as ts\n",
    "from flask import Flask\n",
    "from flask_cors import *\n",
    "from flask import request\n",
    "app = Flask(__name__)\n",
    "CORS(app, supports_credentials=True)\n",
    "\n",
    "def get_data(ID, cache_folder='data'):\n",
    "    ## 判断路径是否存在\n",
    "    if not os.path.exists(cache_folder):\n",
    "        os.mkdir(cache_folder)\n",
    "    ## 生成当前系统时间\n",
    "    now = datetime.datetime.now()\n",
    "    now_str = now.strftime('%Y-%m-%d')\n",
    "    last_str = datetime.datetime(year=now.year-1, month=now.month, day=now.day).strftime('%Y-%m-%d')\n",
    "    ## 判断文件是否存在\n",
    "    file_path = os.path.join(cache_folder, f'{ID}.csv')\n",
    "    if os.path.exists(file_path): # 存在即读取\n",
    "        cache_data = pd.read_csv(file_path)\n",
    "        cache_data = cache_data.set_index('date') # 设置索引\n",
    "        cache_data[(cache_data.index >= last_str) & (cache_data.index <= now_str)] # 取出时间间隔\n",
    "    else: # 不存在则获取并缓存\n",
    "        # 此处为了简单，还是从前一年获取，理论上最好全部后缓存\n",
    "        cache_data = ts.get_hist_data(ID, start=last_str) # 获取时间间隔数据\n",
    "        cache_data.to_csv(file_path)\n",
    "    return cache_data\n",
    "\n",
    "@app.route('/')\n",
    "def hello():\n",
    "    return 'Welcome to My Watchlist!'\n",
    "\n",
    "@app.route('/stock', methods=[\"GET\"])\n",
    "def getStock():\n",
    "    begin = time.time()\n",
    "    \n",
    "    ## 获取时间\n",
    "    now = datetime.datetime.now()\n",
    "    now_str = now.strftime('%Y-%m-%d')\n",
    "    last_str = datetime.datetime(year=now.year-1, month=now.month, day=now.day).strftime('%Y-%m-%d')\n",
    "    ## 接受传参\n",
    "    ID = request.args.get(\"ID\")\n",
    "    hist = get_data(ID)\n",
    "    data = []\n",
    "    hist.reset_index().apply(lambda x: data.append([str(x['date']), str(x['open']), str(x['close']), \n",
    "                                                     str(x['price_change']), str(x['p_change']), str(x['low']), \n",
    "                                                     str(x['high'])]),  axis=1)\n",
    "    end = time.time()\n",
    "    print('耗时', end-begin, '秒')\n",
    "    return str(data)\n",
    "\n",
    "app.run(host='0.0.0.0', port=5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11bd0cee-36c5-4d9d-86b7-51d005ec7218",
   "metadata": {},
   "source": [
    "## 下一步计划"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d1a5366-0edf-4139-9d59-dc8d5b3fc66b",
   "metadata": {},
   "source": [
    "优先级：高，业务价值\n",
    "- 1 表单无法设置时间，查看该某股票指定时间段的K线图，并增加复权项\n",
    "- 2 缓存的逻辑需要优化，应当离线去同步下所有股票的最新全部数据\n",
    "- 3 用户个性化定制不足，比如增加自选股、股票预警等功能，需要配置mysql数据库"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52c076f1-4f38-4ec1-80d5-75680f2e5cda",
   "metadata": {},
   "source": [
    "优先级：中，增加功能\n",
    "- 4 高并发问题，使用flask面对高并发可能存在问题，需要考虑用django、springboot等成熟架构，并增加redis缓存\n",
    "- 5 前端界面功能较少，所以使用了最简单的html、css、js，后期复杂度提升后需要考虑使用vue react等成熟前端架构"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41072ab4-11a8-4bbf-89d5-ab24da620369",
   "metadata": {},
   "source": [
    "优先级：低，优化架构\n",
    "- 6 股票当前的数据粒度在天，且数据不够丰富，后期可以同步更多的财务数据，并将股票时间粒度精确到tick，需要采用更成熟的大数据存储计算架构，如hadoop、dolphineDB|、tdengine、hive、spark、clickhouse等"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b72acb05-37a4-4613-8bc9-0849d8a50c15",
   "metadata": {},
   "source": [
    "凤凰架构：https://icyfenix.cn/"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "afan_test",
   "language": "python",
   "name": "afan_test"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  },
  "toc-autonumbering": true
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
